{ "cells": [ { "cell_type": "markdown", "id": "142de0bb-6053-4122-9777-ea9db5dd61ce", "metadata": {}, "source": [ "# ANISE\n", "\n", "ANISE is a modern rewrite of NAIF SPICE, written in Rust and providing interfaces to other languages including Python.\n", "\n", "Evidently, this tutorial applies to the Python usage of ANISE.\n", "\n", "## Goal\n", "By the end of this tutorial, you should know how to build a data frame containing the Sun probe Earth angle of a given spacecraft BSP and plot that information. Your exercise will be to confirm that this calculation is correct by computing the Sun elevation at nadir below the spacecraft as detailed in tutorial 04.## Loading the latest orientation and planetary data\n", "\n", "Let's start by installing ANISE: `pip install anise`" ] }, { "cell_type": "markdown", "id": "20351a7f-e6b0-4d0c-ac6b-0cfabb6d76ca", "metadata": {}, "source": [ "## Load a BSP containing a spacecraft trajectory\n", "\n", "In this tutorial, we will use the `gmat-hermite.bsp` file which contains some trajectory data build in GMAT and used in ANISE for validation purposes. Although the Sun probe Earth angle _typically_ applies to spacecraft trajectories, the calculation works for any two objects." ] }, { "cell_type": "code", "execution_count": 2, "id": "59c15415-c54d-465f-962b-585e870d296b", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "=== SPK #0 ===\n", "┌─────────────┬──────────────────────┬─────────────┬───────────────────────────────────┬───────────────────────────────────┬────────────┬──────────────────────┐\n", "│ Name │ Target │ Center │ Start epoch │ End epoch │ Duration │ Interpolation kind │\n", "├─────────────┼──────────────────────┼─────────────┼───────────────────────────────────┼───────────────────────────────────┼────────────┼──────────────────────┤\n", "│ SPK_SEGMENT │ body -10000001 J2000 │ Earth J2000 │ 2000-01-01T12:00:32.183927328 TDB │ 2000-01-01T15:20:32.183931556 TDB │ 3 h 20 min │ Hermite Unequal Step │\n", "└─────────────┴──────────────────────┴─────────────┴───────────────────────────────────┴───────────────────────────────────┴────────────┴──────────────────────┘\n", "=== SPK #1 ===\n", "┌────────────────┬─────────────────────────────┬─────────��─────────────────────┬───────────────────────────────────┬───────────────────────────────────┬─────────────┬────────────────────┐\n", "│ Name │ Target │ Center │ Start epoch │ End epoch │ Duration │ Interpolation kind │\n", "├────────────────┼─────────────────────────────┼───────────────────────────────┼───────────────────────────────────┼───────────────────��───────────────┼─────────────┼────────────────────┤\n", "│ DE-0440LE-0440 │ Mercury J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Venus J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Earth-Moon Barycenter J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Mars Barycenter J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Jupiter Barycenter J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Saturn Barycenter J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Uranus Barycenter J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Neptune Barycenter J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Pluto Barycenter J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Sun J2000 │ Solar System Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Moon J2000 │ Earth-Moon Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ Earth J2000 │ Earth-Moon Barycenter J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ body 199 J2000 │ Mercury J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "│ DE-0440LE-0440 │ body 299 J2000 │ Venus J2000 │ 1849-12-26T00:00:00.000046818 TDB │ 2150-01-21T23:59:59.999955683 TDB │ 109600 days │ Chebyshev Triplet │\n", "└────────────────┴─────────────────────────────┴───────────────────────────────┴───────────────────────────────────┴───────────────────────────────────┴─────────────┴────────────────────┘\n" ] } ], "source": [ "from anise import MetaAlmanac\n", "almanac = MetaAlmanac.latest().load(\"../../data/gmat-hermite.bsp\")\n", "almanac.describe(spk=True)" ] }, { "cell_type": "markdown", "id": "9f1d744b-461a-4a38-9d24-b5e989747355", "metadata": {}, "source": [ "We have successfully loaded two BSP files, one with the planetary data and the other with spacecraft data. We now know that this spacecraft has the ID `-10000001`. We can actually query the Almanac for the precise start and stop epochs (returned as hifitime `Epoch` objects) of this ID in our loaded files." ] }, { "cell_type": "code", "execution_count": 3, "id": "c85fc5ec-7b54-4c00-9a1a-9722d7a80cd1", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2000-01-01T11:59:28.000000021 UTC 2000-01-01T15:19:28.000000226 UTC\n" ] } ], "source": [ "start_epoch, stop_epoch = almanac.spk_domain(-10000001)\n", "print(start_epoch, stop_epoch)" ] }, { "cell_type": "markdown", "id": "414d228b-1b69-4352-b415-0ebcd71a669c", "metadata": {}, "source": [ "The Sun Probe Earth angle is the angle between a probe and the Sun and the probe the Earth. It allows one to know whether the point exactly nadir (i.e. below) the spacecraft is illuminated by the Sun or not. This is helpful information if the spacecraft carries a visible light camera and needs to take pictures when it's daytime below the spacecraft.\n", "\n", "Let's look at the signature of this function." ] }, { "cell_type": "code", "execution_count": 7, "id": "40176b6b-dfb8-4d9d-a6c2-93cc5c8cd751", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\u001b[0;31mSignature:\u001b[0m \u001b[0malmanac\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msun_angle_deg\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mtarget_id\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mobserver_id\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mepoch\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mDocstring:\u001b[0m\n", "Returns the angle (between 0 and 180 degrees) between the observer and the Sun, and the observer and the target body ID.\n", "This computes the Sun Probe Earth angle (SPE) if the probe is in a loaded, its ID is the \"observer_id\", and the target is set to its central body.\n", "\n", "# Geometry\n", "If the SPE is greater than 90 degrees, then the celestial object below the probe is in sunlight.\n", "\n", "## Sunrise at nadir\n", "```text\n", "Sun\n", " | \\ \n", " | \\\n", " | \\\n", " Obs. -- Target\n", "```\n", "## Sun high at nadir\n", "```text\n", "Sun\n", " \\ \n", " \\ __ θ > 90\n", " \\ \\\n", " Obs. ---------- Target\n", "```\n", "\n", "## Sunset at nadir\n", "```text\n", " Sun\n", " / \n", " / __ θ < 90\n", " / /\n", " Obs. -- Target\n", "```\n", "\n", "# Algorithm\n", "1. Compute the position of the Sun as seen from the observer\n", "2. Compute the position of the target as seen from the observer\n", "3. Return the arccosine of the dot product of the norms of these vectors.\n", "\u001b[0;31mType:\u001b[0m builtin_function_or_method" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "almanac.sun_angle_deg?" ] }, { "cell_type": "markdown", "id": "b36bb3ec-8f8a-4298-90ea-2579c3f74ea5", "metadata": {}, "source": [ "One will note that this function is generic to what the \"probe\" SPK ID is (\"observer\") and what its central object should be instead of Earth (\"target\").\n", "\n", "The other crucial point here is that this is one of the few functions where the object _ID_ is required instead of a frame. This is because the Almanac will compute everything in the J2000 frame. Don't worry, if you have frame objects instead, you may use the `sun_angle_deg_from_frame` function instead.\n", "\n", "Let's see what is the SPE of our spacecraft at the start of the trajectory.\n" ] }, { "cell_type": "code", "execution_count": 6, "id": "0366c5b9-cf4d-473e-9385-3a425fd554bf", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "83.87312777296376" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from anise.astro.constants import CelestialObjects\n", "almanac.sun_angle_deg(-10000001, CelestialObjects.EARTH, start_epoch)" ] }, { "cell_type": "markdown", "id": "c18f00cf-fdc7-4050-b8b4-4f951e6e11e6", "metadata": {}, "source": [ "A angle of less than 90 degrees means that the nadir point is in the darkness. Let's look at the evolution of the SPE over the duration of the trajectory." ] }, { "cell_type": "markdown", "id": "8d8a8d44-b433-4955-a0e5-81988decafce", "metadata": { "jp-MarkdownHeadingCollapsed": true }, "source": [ "## Package installation for plotting" ] }, { "cell_type": "code", "execution_count": 12, "id": "b91b712a-3fe7-41a9-9e7d-78cabb756b9d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Requirement already satisfied: polars[plot] in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (0.20.4)\n", "Requirement already satisfied: hvplot in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (0.9.1)\n", "Collecting geoviews\n", " Downloading geoviews-1.11.0-py2.py3-none-any.whl (511 kB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m511.2/511.2 kB\u001b[0m \u001b[31m690.4 kB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m kB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m:01\u001b[0m\n", "\u001b[?25hRequirement already satisfied: bokeh>=1.0.0 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (3.3.3)\n", "Requirement already satisfied: colorcet>=2 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (3.0.1)\n", "Requirement already satisfied: holoviews>=1.11.0 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (1.18.1)\n", "Requirement already satisfied: pandas in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (2.1.4)\n", "Requirement already satisfied: numpy>=1.15 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (1.26.3)\n", "Requirement already satisfied: packaging in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (23.2)\n", "Requirement already satisfied: panel>=0.11.0 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (1.3.6)\n", "Requirement already satisfied: param<3.0,>=1.12.0 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from hvplot) (2.0.1)\n", "Collecting cartopy>=0.18.0 (from geoviews)\n", " Downloading Cartopy-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.9 MB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m11.9/11.9 MB\u001b[0m \u001b[31m14.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0mm eta \u001b[36m0:00:01\u001b[0m[36m0:00:01\u001b[0m\n", "\u001b[?25hCollecting shapely (from geoviews)\n", " Downloading shapely-2.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.5 MB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.5/2.5 MB\u001b[0m \u001b[31m54.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m31m72.7 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\n", "\u001b[?25hCollecting pyproj (from geoviews)\n", " Downloading pyproj-3.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (8.6 MB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m8.6/8.6 MB\u001b[0m \u001b[31m13.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0mm eta \u001b[36m0:00:01\u001b[0m0:01\u001b[0m:01\u001b[0m\n", "\u001b[?25hRequirement already satisfied: xyzservices in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from geoviews) (2023.10.1)\n", "Requirement already satisfied: Jinja2>=2.9 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from bokeh>=1.0.0->hvplot) (3.1.2)\n", "Requirement already satisfied: contourpy>=1 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from bokeh>=1.0.0->hvplot) (1.2.0)\n", "Requirement already satisfied: pillow>=7.1.0 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from bokeh>=1.0.0->hvplot) (10.2.0)\n", "Requirement already satisfied: PyYAML>=3.10 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from bokeh>=1.0.0->hvplot) (6.0.1)\n", "Requirement already satisfied: tornado>=5.1 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from bokeh>=1.0.0->hvplot) (6.4)\n", "Collecting matplotlib>=3.4 (from cartopy>=0.18.0->geoviews)\n", " Downloading matplotlib-3.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (11.6 MB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m11.6/11.6 MB\u001b[0m \u001b[31m47.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0mm eta \u001b[36m0:00:01\u001b[0m[36m0:00:01\u001b[0m\n", "\u001b[?25hCollecting pyshp>=2.1 (from cartopy>=0.18.0->geoviews)\n", " Downloading pyshp-2.3.1-py2.py3-none-any.whl (46 kB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m46.5/46.5 kB\u001b[0m \u001b[31m14.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: pyct>=0.4.4 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from colorcet>=2->hvplot) (0.5.0)\n", "Requirement already satisfied: pyviz-comms>=0.7.4 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from holoviews>=1.11.0->hvplot) (3.0.0)\n", "Requirement already satisfied: python-dateutil>=2.8.2 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from pandas->hvplot) (2.8.2)\n", "Requirement already satisfied: pytz>=2020.1 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from pandas->hvplot) (2023.3.post1)\n", "Requirement already satisfied: tzdata>=2022.1 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from pandas->hvplot) (2023.4)\n", "Requirement already satisfied: markdown in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (3.5.2)\n", "Requirement already satisfied: markdown-it-py in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (3.0.0)\n", "Requirement already satisfied: linkify-it-py in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (2.0.2)\n", "Requirement already satisfied: mdit-py-plugins in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (0.4.0)\n", "Requirement already satisfied: requests in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (2.31.0)\n", "Requirement already satisfied: tqdm>=4.48.0 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (4.66.1)\n", "Requirement already satisfied: bleach in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (6.1.0)\n", "Requirement already satisfied: typing-extensions in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from panel>=0.11.0->hvplot) (4.9.0)\n", "Requirement already satisfied: certifi in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from pyproj->geoviews) (2023.11.17)\n", "Requirement already satisfied: MarkupSafe>=2.0 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from Jinja2>=2.9->bokeh>=1.0.0->hvplot) (2.1.3)\n", "Collecting cycler>=0.10 (from matplotlib>=3.4->cartopy>=0.18.0->geoviews)\n", " Downloading cycler-0.12.1-py3-none-any.whl (8.3 kB)\n", "Collecting fonttools>=4.22.0 (from matplotlib>=3.4->cartopy>=0.18.0->geoviews)\n", " Downloading fonttools-4.47.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.9 MB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m4.9/4.9 MB\u001b[0m \u001b[31m49.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m31m56.4 MB/s\u001b[0m eta \u001b[36m0:00:01\u001b[0m\n", "\u001b[?25hCollecting kiwisolver>=1.3.1 (from matplotlib>=3.4->cartopy>=0.18.0->geoviews)\n", " Downloading kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.4/1.4 MB\u001b[0m \u001b[31m47.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hCollecting pyparsing>=2.3.1 (from matplotlib>=3.4->cartopy>=0.18.0->geoviews)\n", " Downloading pyparsing-3.1.1-py3-none-any.whl (103 kB)\n", "\u001b[2K \u001b[38;2;114;156;31m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m103.1/103.1 kB\u001b[0m \u001b[31m42.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", "\u001b[?25hRequirement already satisfied: six>=1.5 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from python-dateutil>=2.8.2->pandas->hvplot) (1.16.0)\n", "Requirement already satisfied: webencodings in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from bleach->panel>=0.11.0->hvplot) (0.5.1)\n", "Requirement already satisfied: uc-micro-py in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from linkify-it-py->panel>=0.11.0->hvplot) (1.0.2)\n", "Requirement already satisfied: mdurl~=0.1 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from markdown-it-py->panel>=0.11.0->hvplot) (0.1.2)\n", "Requirement already satisfied: charset-normalizer<4,>=2 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from requests->panel>=0.11.0->hvplot) (3.3.2)\n", "Requirement already satisfied: idna<4,>=2.5 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from requests->panel>=0.11.0->hvplot) (3.6)\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/chris/Workspace/nyx-space/anise/anise-py/.venv/lib64/python3.11/site-packages (from requests->panel>=0.11.0->hvplot) (2.1.0)\n", "Installing collected packages: shapely, pyshp, pyproj, pyparsing, kiwisolver, fonttools, cycler, matplotlib, cartopy, geoviews\n", "Successfully installed cartopy-0.22.0 cycler-0.12.1 fonttools-4.47.2 geoviews-1.11.0 kiwisolver-1.4.5 matplotlib-3.8.2 pyparsing-3.1.1 pyproj-3.6.1 pyshp-2.3.1 shapely-2.0.2\n", "\n", "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.1.2\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m23.3.2\u001b[0m\n", "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n", "Note: you may need to restart the kernel to use updated packages.\n" ] } ], "source": [ "%pip install \"polars[plot]\" hvplot geoviews # geoviews for geographic data" ] }, { "cell_type": "markdown", "id": "70a3ddf6-18d7-4f94-94c4-14d73018b2ea", "metadata": {}, "source": [ "## Evolution of SPE over time\n", "\n", "We'll plot the change in Sun probe Earth angle over time. We'll also grab the latitude and longitude data so we can plot the position of the spacecraft above the Earth at those times (as a separate plot)." ] }, { "cell_type": "code", "execution_count": 38, "id": "55ec0bf7-2ec8-480f-89be-cd698d0d1e55", "metadata": {}, "outputs": [], "source": [ "from anise.time import TimeSeries, Unit, Epoch\n", "from anise.astro import Frame\n", "from anise.astro.constants import Frames, Orientations\n", "\n", "import polars as pl\n", "from datetime import datetime\n", "\n", "def hifitime_to_datetime(e: Epoch) -> datetime:\n", " return datetime.fromisoformat(str(e).replace(\" UTC\", \"\")[:23])\n", "\n", "epochs = []\n", "spe_deg = []\n", "lat_deg = []\n", "long_deg = []\n", "\n", "# Let's be sure to load the PCK data, which includes the frame information such as the shape of\n", "# the ellipsoid and how to compute the rotation of the body fixed frames\n", "almanac = almanac.load(\"../../data/pck08.pca\")\n", "\n", "SC_ID = -10000001\n", "SC_J2K = Frame(SC_ID, Orientations.J2000)\n", "\n", "for epoch in TimeSeries(start_epoch, stop_epoch, Unit.Minute*1, inclusive=True):\n", " epochs += [hifitime_to_datetime(epoch)]\n", " spe_deg += [almanac.sun_angle_deg(CelestialObjects.EARTH, SC_ID, epoch)]\n", " # Grab position of the spacecraft in the IAU Earth frame\n", " sc_iau_earth = almanac.transform(SC_J2K, Frames.IAU_EARTH_FRAME, epoch)\n", " lat_deg += [sc_iau_earth.latitude_deg()]\n", " long_deg += [sc_iau_earth.longitude_deg()]" ] }, { "cell_type": "code", "execution_count": 39, "id": "4f6a34a7-ddae-430d-a138-e3111e7b696c", "metadata": {}, "outputs": [], "source": [ "# Build the data frame\n", "df = pl.DataFrame(\n", " {\n", " 'Epoch': epochs,\n", " 'Sun Probe Earth angle (deg)': spe_deg,\n", " 'Latitude (deg)': lat_deg,\n", " 'Longitude (deg)': long_deg\n", " }\n", ")" ] }, { "cell_type": "code", "execution_count": 43, "id": "614ff2ee-593c-41a6-8932-72671c430ac7", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":Curve [Epoch] (Sun Probe Earth angle (deg),Latitude (deg),Longitude (deg))" ] }, "execution_count": 43, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2696" } }, "output_type": "execute_result" } ], "source": [ "import hvplot.polars\n", "from bokeh.models.formatters import DatetimeTickFormatter\n", "\n", "formatter = DatetimeTickFormatter(days='%d/%m') # Make the world a better place\n", "\n", "df.hvplot(x=\"Epoch\", y=\"Sun Probe Earth angle (deg)\", xformatter=formatter, \n", " title=\"Sun probe Earth angle over time\", hover_cols=[\"Latitude (deg)\", \"Longitude (deg)\"])" ] }, { "cell_type": "code", "execution_count": 41, "id": "abb43538-5c41-4481-96dc-eefcb36764a2", "metadata": {}, "outputs": [ { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":Overlay\n", " .WMTS.I :WMTS [Longitude,Latitude]\n", " .Points.I :Points [Longitude (deg),Latitude (deg)] (Epoch,Sun Probe Earth angle (deg))" ] }, "execution_count": 41, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p2520" } }, "output_type": "execute_result" } ], "source": [ "df.hvplot.points('Longitude (deg)', 'Latitude (deg)', geo=True, color='red', tiles='ESRI', xlim=(0, 360), ylim=(-60, 60), hover_cols=[\"Epoch\", \"Sun Probe Earth angle (deg)\"])" ] }, { "cell_type": "markdown", "id": "4e64369b-ae0e-4977-aec7-a0722e9a06a5", "metadata": {}, "source": [ "## Exercise\n", "\n", "The goal of this exercise is to show that the SPE is essentially the Sun elevation angle from the position exactly nadir of the vehicle plus 90 degrees (or so, since the Earth isn't a perfect sphere). It also shows you how to combine the different functionality you've seen with the other tutorials to solve similar problem.\n", "\n", "_Note:_ this is the `verify_geometry` Rust test, but rebuilt in Python.\n", "\n", "1. For the whole spacecraft trajectory, build the locality exactly nadir of it at each epoch (remember that a `TimeSeries` instance can only be used once, so you'll need to rebuild a new one). For this step, initialize a new `Orbit` instance from the latitude and longitude constructor using the position of the spacecraft in the IAU Earth frame as we did above.\n", "2. At each epoch, grab the state of the Sun as seen from the Earth (both can be in the J2000 frame since the AER computation will transform the states into the correct frames anyway).\n", "3. Call the azimuth, elevtion, and range function of your loaded Almanac, and store the elevation of the Sun as seen from the point exactly nadir of the spacecraft.\n", "4. Plot the elevation data in degrees compared to the SPE angle calculated above." ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": ".venv" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.4" } }, "nbformat": 4, "nbformat_minor": 5 }